package com.bnzj.cloud.business.core.service;

import com.bnzj.cloud.business.core.persistence.entity.SysResourceMeta;
import com.bnzj.cloud.business.core.persistence.entity.SysResource;
import com.bnzj.cloud.business.core.persistence.entity.SysRole;
import com.bnzj.cloud.business.core.persistence.entity.SysRoleResource;
import com.bnzj.cloud.business.core.persistence.repository.SysResourceMetaRepository;
import com.bnzj.cloud.business.core.persistence.repository.SysResourceRepository;
import com.bnzj.cloud.business.core.persistence.repository.SysResourceRoleRepository;
import com.bnzj.cloud.business.core.persistence.repository.SysRoleRepository;
import com.bnzj.core.persistence.BaseService;
import com.bnzj.core.persistence.util.EntityUtils;
import com.bnzj.core.rest.UserInfo;
import com.bnzj.core.util.FbConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.Tuple;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class SysResourceService extends BaseService<SysResourceRepository, SysResource, Long> {

    @Autowired
    private SysRoleRepository sysRoleRepository;
    @Autowired
    private SysResourceRoleRepository sysResourceRoleRepository;

    public List<SysResource> findByUserAndUrl(String account, String url) {
        return repository.findByUserAndUrl(account, url);
    }

    public List<SysResource> findChildByUserAndUrl(String account, String url) {
        return repository.findChildByUserAndUrl(account, url);
    }

    public List<SysResource> findByUserAndPids(String account, long... pids) {
        return repository.findByUserAndPids(account, pids);
    }

    public List<SysResource> findByUserAdmin(long... pids) {
        return repository.findByUserAdmin(pids);
    }

    public Optional<SysResource> findByPidAndUrl(long pid, String url) {
        return repository.findByPidAndUrl(pid, url);
    }

    public List<SysResource> getMenuByCurrentUser(String account) {
        //为了排序，否则使用findByUserAndPids方法即可
        List<SysResource> menuList = findByUserAndPids(account, SysResource.getRoot().getId());
        menuList.forEach(menu -> menu.setChildren(findByUserAndPids(account, menu.getId())));
        return menuList;
    }

    public List<SysResource> getMenuByCurrentUserAdmin() {
        List<SysResource> menuList = repository.findByUserAdmin(SysResource.getRoot().getId());
        menuList.forEach(menu -> menu.setChildren(findByUserAdmin(menu.getId())));
        return menuList;
    }

    public List<Tuple> findAllUrlAndRoleCode() {
        return repository.findAllUrlAndRoleCode();
    }

    public List<SysResource> findAllByUserAccount(String account) {
        return repository.findAllByUserAccount(account);
    }


    @Transactional(rollbackFor = Exception.class)
    public void saveResource(SysResource sysResource) {
        SysResource resourceDb = this.repository.save(sysResource);
//        管理员具有所有菜单权限
        SysRoleResource sysRoleResource = new SysRoleResource();
        SysRole adminRole = sysRoleRepository.findByCode(FbConstant.ADMIN);
        sysRoleResource.setResourceId(resourceDb.getId());
        sysRoleResource.setRoleId(adminRole.getId());
        EntityUtils.saveBefore(sysRoleResource, sysResource.getCreatorName(), sysResource.getCreator());
        sysResourceRoleRepository.save(sysRoleResource);
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveRoleResource(String roleId, String resourceIds, String account, String name) {
        String[] resourceArr = resourceIds.split(",");
        if(resourceArr.length > 0) {
            sysResourceRoleRepository.deleteByRoleId(Long.parseLong(roleId));
            for(String resourceId : resourceArr) {
                SysRoleResource sysRoleResource = new SysRoleResource();
                sysRoleResource.setRoleId(Long.parseLong(roleId));
                sysRoleResource.setResourceId(Long.parseLong(resourceId));
                EntityUtils.saveBefore(sysRoleResource, account, name);
                sysResourceRoleRepository.save(sysRoleResource);
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveResourceNew(SysResource sysResource) {
        this.repository.save(sysResource);
//        管理员具有所有菜单权限
        /*SysRoleResource sysRoleResource = new SysRoleResource();
        SysRole adminRole = sysRoleRepository.findByCode(FbConstant.ADMIN);
        sysRoleResource.setResourceId(resourceDb.getId());
        sysRoleResource.setRoleId(adminRole.getId());
        EntityUtils.saveBefore(sysRoleResource, sysResource.getCreatorName(), sysResource.getCreator());
        sysResourceRoleRepository.save(sysRoleResource);*/
    }

    public List<SysResource> getMenuTree() {
        List<SysResource> generateTreeMenu = repository.findAll(Sort.by(Sort.Direction.ASC, "sequence"));
        List<SysResource> sysResources = generateTreeMenu(generateTreeMenu);
        return sysResources;
    }

    private List<SysResource> generateTreeMenu(List<SysResource> treeNodes) {
        List<SysResource> rootNodes = treeNodes.stream().filter(node -> SysResource.getRoot().getId().equals(node.getPid())).collect(Collectors.toList());
        rootNodes.forEach(root -> findChildren(root, treeNodes));
        return rootNodes;
    }

    private void findChildren(SysResource root, List<SysResource> treeNodes) {
        List<SysResource> children = treeNodes.stream().filter(node -> root.getId().equals(node.getPid())).collect(Collectors.toList());
        root.setChildren(children);
        if (children != null) {
            children.forEach(child -> findChildren(child, treeNodes));
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Long id) {
        this.repository.deleteById(id);
    }

    public List<SysResource> getCurrentUserButton(String account, Integer type) {
        return this.repository.findCurrentUserButton(account, type);
    }

    public List<SysResource> getCurrentUserButtonAdmin(Integer type) {
        return this.repository.findCurrentUserButtonAdmin(type);
    }

    @Autowired
    private SysResourceMetaRepository resourceMetaRepository;

    public void saveMenuRelMeta(Long menuId, List<Long> metas) {
        Optional<SysResource> menu = this.repository.findById(menuId);
        SysResource authResourceMenu = menu.get();
        List<SysResourceMeta> metaList = resourceMetaRepository.findByIdIn(metas);
        authResourceMenu.setMetaSet(new HashSet<>(metaList));
        this.repository.save(authResourceMenu);
    }
}
